﻿using System;
using System.Collections.Generic;
using System.Text;
using Stauffware.Common.Core;
using Stauffware.Common.Xml.Xerialization;

namespace XmlUnitTests.TestObjects
{
	//	All of the classes in this file serve as test data for Xerialization.
	//
	//	See ../documentation/UnitTests.xls for a list of abbreviations used in the names.

	//=================================================================================

	/// <summary> A non-flags (single-value) enum. </summary>
	public enum Enm_1
	{
		Foo, Bar, Foobar
	}

	/// <summary> A Flags (bit field) enum. </summary>
	[Flags]
	public enum Fen_1
	{
		None = 0,
		Salt=1, Pepper=2, Butter=4,
		All = Salt | Pepper | Butter
	}

	//=================================================================================
	/// <summary>
	/// An abstract class.
	/// </summary>

	[XerialType]
	public abstract class ClsAbs_1
	{
		public Int32 PubFldI32 = 69;
		
		protected double ProFldF64 = 3.1415926;
		
		private string PrvFldStr = "don't look at me";

		public readonly Enm_1 PubRdoFldEnm = Enm_1.Foobar;

		public bool PubPrpBoo { get { return this.PrvFldBoo; } set { this.PrvFldBoo = value; } }
		private bool PrvFldBoo;

		protected Fen_1 ProPrpFen { get { return this.PrvPrpFen; } set { this.PrvPrpFen = value; } }
		private Fen_1 PrvPrpFen;

		private void this_method_exists_only_to_suppress_compiler_warnings ( )
		{
			int n = this.PrvFldStr.Length;
		}
	}

	//=================================================================================
	/// <summary>
	/// A concrete class derived from an abstract class.
	/// </summary>

	[XerialType]
	public class Cls_1a : ClsAbs_1
	{
		public Cls_1a (Fen_1 fen)
		{
			this.ProPrpFen = fen;
		}

		// NOTE: without a default constructor, *no* constructor will be called, nor will
		//			field initialization happen (i.e. PubRdoFldEnm).
		private Cls_1a ( ) { }
	}

	//=================================================================================
	/// <summary>
	/// An empty concrete class derived from an abstract class.
	/// </summary>

	[XerialType]
	public class Cls_1b : ClsAbs_1
	{
	}

	//=================================================================================
	/// <summary>
	/// An immutable structure.
	/// </summary>

	[XerialType(XmlName = "ConSct_1")]
	public struct ConSct_1
	{
		public readonly decimal DecFld;
		public string StrPrp { get; private set; }
		public string StrPrp2 { get; set; }

		public ConSct_1 (decimal d, string s)
			: this()	// necessary for initialization of automatic property StrPrp
		{
			StrPrp = s;
			this.DecFld = d;
		}

		public override string ToString ( )
		{
			return "ConSct_1 { " +
					"DecFld = " + ErrorUtils.ValueToString(this.DecFld) +
					"; StrPrp = " + ErrorUtils.ValueToString(this.StrPrp) +
					"; StrPrp2 = " + ErrorUtils.ValueToString(this.StrPrp2) +
					"}";
		}
	}

	//=================================================================================
	/// <summary>
	/// Class for testing different MemberValueEncodings.
	/// </summary>

	[XerialType]
	public class Encodings
	{
		[XerialMember(Encoding=MemberValueEncoding.Attribute)]
		public byte ByteAsAttr = 17;

		//[XerialMember(Encoding=MemberValueEncoding.ImplicitMemberName)]
		//public short ShortImpName = 23;

		[XerialMember(Encoding=MemberValueEncoding.ImplicitValueType)]
		public int IntImpType = 69;

		[XerialMember(Encoding=MemberValueEncoding.NestedElements)]
		public long Nested = 5280;
	}

	//=================================================================================
	/// <summary>
	/// A class derived from a generic class.
	/// </summary>

	[XerialType]
	public class DerivedFromGeneric : List<string>
	{
		public int Foo;
	}

	//=================================================================================
	/// <summary>
	/// This class contains instances of all the others.
	/// </summary>

	[XerialType]
	public class MainClass
	{
		public DerivedFromGeneric DerFromGen = new DerivedFromGeneric();
		public List<ClsAbs_1> PubLstCls = new List<ClsAbs_1>();
		public Encodings Encodings;
		[XerialMember(Encoding=MemberValueEncoding.ImplicitValueType)]
		public ConSct_1 Immutable;
		public Rational Fraction;

		public MainClass ()
		{
			this.PubLstCls.Add(new Cls_1a(Fen_1.None));
			this.PubLstCls.Add(new Cls_1b());
			this.PubLstCls.Add(new Cls_1a(Fen_1.All));
			this.Encodings = new Encodings();
			this.Fraction = new Rational(17, 23);
			this.Immutable = new ConSct_1(3.14159M, "pi");
		}

		public static void InitializeContext (XerialContext context)
		{
			context.TypeMappings.Add(new RationalXMapping(context));

			context.TypeMappings.AddIfNeeded(XerialTypes);
		}

		private static readonly Type[] XerialTypes =
		{
			typeof(ClsAbs_1),	typeof(Cls_1a),	typeof(Cls_1b),	typeof(MainClass),
		};
	}

	//=================================================================================
}
